package com.sy.simpleegg.serialport.coincontroller

import com.sy.coincontroller.controller.status.SaveFlowStatus
import com.sy.coincontroller.controller.status.SaveResult
import com.sy.simpleegg.ext.logFile
import com.sy.simpleegg.serialport.bean.ComData
import com.sy.simpleegg.serialport.coincontroller.bean.CheckBean
import com.sy.simpleegg.serialport.coincontroller.bean.CoinOrderBean
import com.sy.simpleegg.serialport.coincontroller.bean.OutCoinsBean
import com.sy.simpleegg.serialport.coincontroller.bean.OutResultBean
import com.sy.simpleegg.serialport.coincontroller.bean.SaveCoinsBean
import com.sy.simpleegg.serialport.coincontroller.bean.SaveResultBean
import com.sy.simpleegg.serialport.coincontroller.status.OutFlowStatus
import com.sy.simpleegg.serialport.coincontroller.status.OutResult
import com.sy.simpleegg.serialport.coincontroller.status.SnStatus
import com.sy.simpleegg.serialport.coincontroller.util.StatusUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.cnbleu.serialport.SerialPort
import java.util.Queue
import java.util.UUID
import java.util.concurrent.LinkedBlockingDeque

class CoinController(
    portName: String,
    baudrate: SerialPort.BAUDRATE,
    stopb: SerialPort.STOPB,
    datab: SerialPort.DATAB,
    parity: SerialPort.PARITY,
    runHeartBeat: Boolean,
    verNumber: Int = 1,
    speed: Long = 10L
) : BaseCoinController(portName, baudrate, stopb, datab, parity, verNumber, speed) {

    private val TAG = javaClass.simpleName

    override fun onDispenserResp(dispenser1Coins: String, dispenser2Coins: String) {
        currentSaveCoinsBean?.let {
            it.dispenser1Coins = dispenser1Coins.toLong(16)
            it.dispenser2Coins = dispenser2Coins.toLong(16)
        }
    }

    override fun onDispenserRec(dispenser1Enable: String, dispenser2Enable: String) {
        currentSaveCoinsBean?.let {
            saveFlowStatus = if (dispenser1Enable == "00" && dispenser2Enable == "00"){
                SaveFlowStatus.FINISH
            }else{
                SaveFlowStatus.REC
            }
        }
    }

    override fun onOutResp(
        snStatus: String,
        motor1Status: String,
        motor1NeedOutCoins: String,
        motor1RealOutCoins: String,
        motor2Status: String,
        motor2NeedOutCoins: String,
        motor2RealOutCoins: String
    ) {
        outFlowStatus = OutFlowStatus.RESP
        outResp = true
        currentOutCoinsBean?.let {
            it.snStatus = StatusUtil.getSnStatus(snStatus.toInt(16))
            it.motor1Status = StatusUtil.getMotorStatus(motor1Status.toInt(16))
            it.motor1RealOutCoins = motor1RealOutCoins.toLong(16)
            it.motor2Status = StatusUtil.getMotorStatus(motor2Status.toInt(16))
            it.motor2RealOutCoins = motor2RealOutCoins.toLong(16)
        }

//        currentOutCoinsBean?.let {
//
//            when (it.motor1Status){
//                MotorStatus.ABNORMAL -> {
//                    serialControllerListener?.onMotorErr(1)
//                }
//                MotorStatus.FAULT -> {
//                    serialControllerListener?.onMotorErr(1)
//                }
//                else -> {}
//            }
//            when (it.motor2Status){
//                MotorStatus.ABNORMAL -> {
//                    serialControllerListener?.onMotorErr(2)
//                }
//                MotorStatus.FAULT -> {
//                    serialControllerListener?.onMotorErr(2)
//                }
//                else -> {}
//            }
//        }
    }

    override fun onOutRec(
        sn: String,
        motor1NeedOutCoins: String,
        motor2NeedOutCoins: String,
        snStatus: String,
        errCode: String
    ) {
        logFile("接收出币订单：sn=$sn motor1NeedOutCoins=$motor1NeedOutCoins motor2NeedOutCoins=$motor2NeedOutCoins snStatus=$snStatus errCode=$errCode")
        outFlowStatus = OutFlowStatus.REC
//        val remainCount = motor1NeedOutCoins.toLong(16) + motor2NeedOutCoins.toLong(16)
//        val totalNeedOutCoins = currentOutCoinsBean?.motor1NeedOutCoins!! + currentOutCoinsBean?.motor2NeedOutCoins!!
//        val totalRealOutCoins = currentOutCoinsBean?.motor1RealOutCoins!! + currentOutCoinsBean?.motor2RealOutCoins!!
//        val remainCount = totalNeedOutCoins-totalRealOutCoins
        currentOutCoinsBean?.snStatus = StatusUtil.getSnStatus(snStatus.toInt(16))
//        when (StatusUtil.getSnStatus(snStatus.toInt(16))){
//            SnStatus.SHIPPING_COMPLETED -> {
//                if (outType == 1){
//                    serialControllerListener?.outCoinFinish(remainCount, totalRealOutCoins, true)
//                }else if (outType == 2){
//                    serialControllerListener?.onClearCoin(true, totalRealOutCoins)
//                }
//            }
//            SnStatus.SHIPPING_DENIED -> {
//                if (outType == 1){
//                    serialControllerListener?.outCoinFinish(remainCount, totalRealOutCoins, true)
//                }else if (outType == 2){
//                    serialControllerListener?.onClearCoin(true, totalRealOutCoins)
//                }
//            }
//            SnStatus.SHIPPING_ERROR -> {
//                if (outType == 1){
//                    serialControllerListener?.outCoinFinish(remainCount, totalRealOutCoins, true)
//                }else if (outType == 2){
//                    serialControllerListener?.onClearCoin(true, totalRealOutCoins)
//                }
//            }
//            else -> {
//                serialControllerListener?.onOutRec()
//            }
//        }
    }

    override fun onCheckedResp(devStatus: String, motor1Status: String, motor2Status: String) {
        logFile("收到心跳数据：devStatus=$devStatus 马达1状态=$motor1Status 马达2状态=$motor2Status")
        state = false
        checkBean = CheckBean(devStatus, StatusUtil.getMotorStatus(motor1Status.toInt(16)), StatusUtil.getMotorStatus(motor2Status.toInt(16)))
    }

    /**
     * 心跳间隔，正常-10秒 异常-3秒
     */
    private val HEARTBEAT_INTERVAL_CONNECT: Long = 10 * 1000
    /**
     * 心跳间隔，正常-10秒 异常-3秒
     */
    private val HEARTBEAT_INTERVAL_DISCONNECT: Long = 3 * 1000

    /**
     * 马达1状态 0-正常 1-故障
     */
    private var motor1State = 0
    /**
     * 马达2状态 0-正常 1-故障
     */
    private var motor2State = 0
    /**
     * 是否出币结束
     */
    private var isOutFinish: Boolean = true

    /**
     * 协程
     */
    private var coroutineScope: CoroutineScope? = null
    /**
     * 控制板心跳线程
     */
    private var heartBeatJob: Job? = null

    /**
     * 心跳响应状态，发心跳指令前先设置为false，收到心跳响应设置为true
     */
    private var state: Boolean = true
    private var stateCode = 0
    private var errCode = 0

    /**
     * 链接状态
     */
    private var isConnect = false

    private val orderQueue: Queue<CoinOrderBean> = LinkedBlockingDeque<CoinOrderBean>()
    private var handleJob: Job? = null
    private var isLoop = true
    private var default_timeout = 10*1000
    private var save_timeout = 3*1000
    private var outFlowStatus = OutFlowStatus.PREPARE
    private var saveFlowStatus = SaveFlowStatus.PREPARE

    private var outResp = false
    private var handling = false

    private var currentOutCoinsBean: OutCoinsBean? = null
    private var currentSaveCoinsBean: SaveCoinsBean? = null
    private var checkBean: CheckBean? = null

//    private var currentOutSn = ""
//    private var m1NeedOutCoins = 0L
//    private var m2NeedOutCoins = 0L
//    private var m1RealOutCoins = 0L
//    private var m2RealOutCoins = 0L

    init {
        logFile("打开自研控制板，串口号=$portName 波特率=$baudrate 停止位=$stopb 数据位=$datab 校验位=$parity 控制板心跳：${if (runHeartBeat) "开启" else "关闭"}")
        coroutineScope = MainScope()
        initHandleJob()
        if (runHeartBeat) heartBeatLoop()
    }

    fun getConnectState(): Boolean{
        return isConnect
    }

    /**
     * 释放资源
     */
    fun release(){
        close()
        coroutineScope?.cancel()
    }

    /**
     * 设置马达状态
     */
    fun setMotorState(m1State: Boolean, m2State: Boolean){
        motor1State = if (m1State) 0 else 1
        motor2State = if (m2State) 0 else 1
    }

    private fun initHandleJob(){
        handleJob?.cancel()

        handleJob = coroutineScope?.launch (Dispatchers.IO){
            while (isLoop){
                try {
                    run checkSize@{
                        if (orderQueue.size > 0 && !handling) {
                            var orderBean: CoinOrderBean? = null
                            while (orderQueue.poll().also { orderBean = it } != null) {
                                handling = true
                                val sn = orderBean!!.sn
                                val amount = orderBean!!.amount
                                val m1Coins = orderBean!!.m1Coins
                                val m2Conis = orderBean!!.m2Conis
                                val type = orderBean!!.type

                                if (!isConnect){
//                                    serialControllerListener.onOutCoinsErr()
                                    handling = false
                                    return@checkSize
                                }

                                when (type){
                                    1 -> {
                                        val result = outCoinsHandler(sn, amount, m1Coins, m2Conis)
                                        val totalNeedOutCoins = result.outCoinsBean!!.motor1NeedOutCoins + result.outCoinsBean!!.motor2NeedOutCoins
                                        val totalRealOutCoins = result.outCoinsBean!!.motor1RealOutCoins + result.outCoinsBean!!.motor2RealOutCoins
                                        val remainCount = totalNeedOutCoins - totalRealOutCoins
                                        withContext(Dispatchers.Main){
                                            serialControllerListener?.outCoinFinish(remainCount, totalRealOutCoins, true)
                                            serialControllerListener?.onOutResult(when (result.resultCode){
                                                OutResult.COMPLETED -> "出币完成"
                                                OutResult.REFUSE -> "拒绝出币"
                                                OutResult.ERROR -> "出币异常"
                                                OutResult.TIMEOUT -> "出币超时"
                                            })
                                        }
                                    }
                                    2 -> {
                                        val saveResult = saveCoinsHandler()
                                        saveResult.saveCoinsBean?.let {
                                            val realSaveCoins = it.dispenser1Coins + it.dispenser2Coins
                                            withContext(Dispatchers.Main){
                                                serialControllerListener?.saveCoinFinish(realSaveCoins)
                                            }
                                        }
                                        currentSaveCoinsBean = null
                                        when (saveResult.resultCode){
                                            SaveResult.FINISH -> {}
                                            SaveResult.TIMEOUT -> {
                                                saveEnable(false)
                                            }
                                            SaveResult.ERROR -> {
                                                saveEnable(false)
                                            }
                                        }
                                    }
                                    3 -> {
                                        val clearResult = clearCoinsHandler(sn, amount, m1Coins, m2Conis)
                                        val realOutCoins = clearResult.outCoinsBean!!.motor1RealOutCoins + clearResult.outCoinsBean!!.motor2RealOutCoins
                                        refreshClearCoins(true, realOutCoins)
                                    }
                                    else -> {

                                    }
                                }

                                handling = false
                            }
                        }
                    }
                }catch (e: Exception){
                    e.printStackTrace()
                    logFile("处理出币点单异常：${e.message}")
                }
            }
        }
    }

    private fun heartBeatLoop(){
        try {
            heartBeatJob?.cancel()

            heartBeatJob = coroutineScope?.launch (Dispatchers.IO){
                try {
                    run breaking@{
                        while (true){
                            //出币中，不发送心跳指令，直接返回心跳正常
                            if (handling) {
                                isConnect = true
                                serialControllerListener?.heartBeat(true, stateCode, errCode)
                                delay(5000)
                                return@breaking
                            }

                            state = true
                            checkState()
                            delay(500)
                            isConnect = !state
                            serialControllerListener?.heartBeat(!state, stateCode, errCode)

                            if (state){
                                delay(HEARTBEAT_INTERVAL_DISCONNECT)
                            }else{
                                delay(HEARTBEAT_INTERVAL_CONNECT)
                            }
                        }
                    }
                }catch (e: Exception){
                    e.printStackTrace()
                    logFile("心跳处理异常2：" + e.message)
                }
            }
        }catch (e: Exception){
            e.printStackTrace()
            logFile("心跳处理异常：" + e.message)
        }
    }

    private suspend fun outCoinsHandler(sn: String, amount: Long, m1Coins: Long, m2Coins: Long): OutResultBean {
        return try {
            //指令响应超时
            var overCount = 0
            val interval = 100L
            val maxCount = default_timeout / interval
            var outFinish = false

            outFlowStatus = OutFlowStatus.PREPARE

            currentOutCoinsBean = OutCoinsBean(
                sn,
                StatusUtil.getSnStatus(-1),
                amount,
                StatusUtil.getMotorStatus(-1),
                m1Coins,
                0,
                StatusUtil.getMotorStatus(-1),
                m2Coins,
                0)

            var lastOutCoins = -1L

            outCoin(sn, amount, m1Coins, m2Coins)

            val result = run result@{
                while (true){
                    delay(interval)
                    overCount ++
                    when (outFlowStatus){
                        OutFlowStatus.PREPARE -> {

                        }
                        OutFlowStatus.REC -> {
                            currentOutCoinsBean?.run {
                                when (snStatus){
                                    SnStatus.SHIPPING_COMPLETED -> {
                                        outFinish = true
                                        outFlowStatus = OutFlowStatus.FINISH
                                        return@result OutResult.COMPLETED
                                    }
                                    SnStatus.SHIPPING_DENIED -> {
                                        outFinish = true
                                        outFlowStatus = OutFlowStatus.FINISH
                                        return@result OutResult.REFUSE
                                    }
                                    SnStatus.SHIPPING_ERROR -> {
                                        outFinish = true
                                        outFlowStatus = OutFlowStatus.FINISH
                                        return@result OutResult.ERROR
                                    }
                                    else -> {
                                        serialControllerListener?.onOutRec()
                                    }
                                }
                            }
                        }
                        OutFlowStatus.RESP -> {
                            currentOutCoinsBean?.run {
                                when (snStatus){
                                    SnStatus.SHIPPING_COMPLETED -> {
                                        outFinish = true
                                        outFlowStatus = OutFlowStatus.FINISH
                                        return@result OutResult.COMPLETED
                                    }
                                    SnStatus.SHIPPING_DENIED -> {
                                        outFinish = true
                                        outFlowStatus = OutFlowStatus.FINISH
                                        return@result OutResult.REFUSE
                                    }
                                    SnStatus.SHIPPING_ERROR -> {
                                        outFinish = true
                                        outFlowStatus = OutFlowStatus.FINISH
                                        return@result OutResult.ERROR
                                    }
                                    else -> {
                                        if (outResp){
                                            outResp = false
                                            overCount = 0

                                            val needOutCoins = motor1NeedOutCoins + motor2NeedOutCoins
                                            val realOutCoins = motor1RealOutCoins + motor2RealOutCoins
                                            if (lastOutCoins != realOutCoins){
                                                lastOutCoins = realOutCoins
                                                refreshOutCoins(realOutCoins, needOutCoins)
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        OutFlowStatus.FINISH -> {

                        }
                        OutFlowStatus.TIMEOUT -> {

                        }
                    }

                    if (!outFinish && overCount >= maxCount){
                        outFlowStatus = OutFlowStatus.TIMEOUT
                        return@result OutResult.TIMEOUT
                    }
                }
                OutResult.TIMEOUT
            }

            return OutResultBean(result, currentOutCoinsBean)
        }catch (e: Exception){
            e.printStackTrace()
            logFile("出币流程异常：" + e.message)
            OutResultBean(OutResult.ERROR, null)
        }
    }

    private suspend fun clearCoinsHandler(sn: String, amount: Long, m1Coins: Long, m2Coins: Long): OutResultBean{
        return try {
            //指令响应超时
            var overCount = 0
            val interval = 500L
            val maxCount = default_timeout / interval
            var outFinish = false

            outFlowStatus = OutFlowStatus.PREPARE

            currentOutCoinsBean = OutCoinsBean(
                sn,
                StatusUtil.getSnStatus(-1),
                amount,
                StatusUtil.getMotorStatus(-1),
                m1Coins,
                0,
                StatusUtil.getMotorStatus(-1),
                m2Coins,
                0)
            var lastOutCoins = -1L

            outCoin(sn, amount, m1Coins, m2Coins)

            val result = run result@{
                while (true){
                    delay(interval)
                    overCount ++
                    when (outFlowStatus){
                        OutFlowStatus.PREPARE -> {

                        }
                        OutFlowStatus.REC -> {
                            currentOutCoinsBean?.run {
                                when (snStatus){
                                    SnStatus.SHIPPING_COMPLETED -> {
                                        outFinish = true
                                        outFlowStatus = OutFlowStatus.FINISH
                                        return@result OutResult.COMPLETED
                                    }
                                    SnStatus.SHIPPING_DENIED -> {
                                        outFinish = true
                                        outFlowStatus = OutFlowStatus.FINISH
                                        return@result OutResult.REFUSE
                                    }
                                    SnStatus.SHIPPING_ERROR -> {
                                        outFinish = true
                                        outFlowStatus = OutFlowStatus.FINISH
                                        return@result OutResult.ERROR
                                    }
                                    else -> {
                                        serialControllerListener?.onOutRec()
                                    }
                                }
                            }
                        }
                        OutFlowStatus.RESP -> {
                            currentOutCoinsBean?.run {

                                when (snStatus){
                                    SnStatus.SHIPPING_COMPLETED -> {
                                        outFinish = true
                                        outFlowStatus = OutFlowStatus.FINISH
                                        return@result OutResult.COMPLETED
                                    }
                                    SnStatus.SHIPPING_DENIED -> {
                                        outFinish = true
                                        outFlowStatus = OutFlowStatus.FINISH
                                        return@result OutResult.REFUSE
                                    }
                                    SnStatus.SHIPPING_ERROR -> {
                                        outFinish = true
                                        outFlowStatus = OutFlowStatus.FINISH
                                        return@result OutResult.ERROR
                                    }
                                    else -> {
                                        if (outResp){
                                            outResp = false
                                            overCount = 0

                                            val realOutCoins = motor1RealOutCoins + motor2RealOutCoins
                                            if (lastOutCoins != realOutCoins){
                                                lastOutCoins = realOutCoins
                                                refreshClearCoins(false, realOutCoins)
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        OutFlowStatus.FINISH -> {

                        }
                        OutFlowStatus.TIMEOUT -> {

                        }
                    }

                    if (!outFinish && overCount >= maxCount){
                        outFlowStatus = OutFlowStatus.TIMEOUT
                        return@result OutResult.TIMEOUT
                    }
                }
                OutResult.TIMEOUT
            }

            return OutResultBean(result, currentOutCoinsBean)
        }catch (e: Exception){
            e.printStackTrace()
            logFile("出币流程异常：" + e.message)
            OutResultBean(OutResult.ERROR, null)
        }
    }

    /**
     * 存币处理
     */
    private suspend fun saveCoinsHandler(): SaveResultBean {
        return try {
            //指令响应超时
            var overCount = 0
            val interval = 500L
            val maxCount = save_timeout / interval

            saveFlowStatus = SaveFlowStatus.PREPARE

            currentSaveCoinsBean = SaveCoinsBean()

            var lastSaveCoins = -1L

            saveEnable(true)

            val result = run result@{
                while (true){
                    delay(interval)

                    when (saveFlowStatus){
                        SaveFlowStatus.PREPARE -> {
                            overCount ++
                            if (overCount >= maxCount){
                                return@result SaveResult.TIMEOUT
                            }
                        }
                        SaveFlowStatus.REC -> {
                            currentSaveCoinsBean?.let {
                                val totalSaveCoins = it.dispenser1Coins + it.dispenser2Coins
                                if (totalSaveCoins != lastSaveCoins){
                                    lastSaveCoins = totalSaveCoins
                                    serialControllerListener?.onCoinRefresh(totalSaveCoins, 0, false)
                                }
                            }
                        }
                        SaveFlowStatus.RESP -> {
                            currentSaveCoinsBean?.let {
                                val totalSaveCoins = it.dispenser1Coins + it.dispenser2Coins
                                if (totalSaveCoins != lastSaveCoins){
                                    lastSaveCoins = totalSaveCoins
                                    serialControllerListener?.onCoinRefresh(totalSaveCoins, 0, false)
                                }
                            }
                        }

                        SaveFlowStatus.FINISH -> {
                            return@result SaveResult.FINISH
                        }
                    }
                }
                SaveResult.TIMEOUT
            }

            return SaveResultBean(result, currentSaveCoinsBean)
        }catch (e: Exception){
            e.printStackTrace()
            logFile("存币流程异常：" + e.message)
            SaveResultBean(SaveResult.ERROR, null)
        }
    }

    private suspend fun refreshOutCoins(realOutCoins: Long, needOutCoins: Long = 0){
        withContext(Dispatchers.Main){
            serialControllerListener?.onCoinRefresh(realOutCoins, needOutCoins, true)
        }
    }

    private suspend fun refreshClearCoins(isFinish: Boolean, realOutCoins: Long){
        withContext(Dispatchers.Main){
            serialControllerListener?.onClearCoin(isFinish, realOutCoins)
        }
    }

    /**
     * 校验出币数量
     */
    private fun checkOutCount(count: Long):Boolean{
        if (count <= 0) serialControllerListener?.countErr(count)
        return count > 0
    }



    private fun outCoins(snHex: String, amount: Long, coins1: Long, coins2: Long){
        if (handling){
            return
        }
        orderQueue.add(CoinOrderBean(1, snHex, amount, coins1, coins2))
    }

    fun outCoinM1Business(coins: Long, amount: Long = 100L){
        val sn = UUID.randomUUID().toString().replace("-", "").trim()
        outCoins(sn, amount, coins, 0)
    }

    fun outCoinM2Business(coins: Long, amount: Long = 100L){
        val sn = UUID.randomUUID().toString().replace("-", "").trim()
        outCoins(sn, amount, 0, coins)
    }

    fun outCoinAlternately(coins: Long, amount: Long = 100L){
        val sn = UUID.randomUUID().toString().replace("-", "").trim()
        var coins1 = 0L
        var coins2 = 0L
        when(coins){
            1L -> {
                coins1 = 1L
                coins2 = 0L
            }
            else -> {
                if (coins % 2L == 0L){
                    //偶数
                    coins1 = coins / 2
                    coins2 = coins / 2
                }else{
                    //奇数
                    coins1 = (coins - 1) / 2 + 1;
                    coins2 = (coins - 1) / 2;
                }
            }
        }
        outCoins(sn, amount, coins1, coins2)
    }

    fun clearCoinAlternately(){
        if (handling){
            return
        }
        val coins1 = 65535L
        val coins2 = 65535L
        val amount = coins1*100 + coins2*100
        val sn = UUID.randomUUID().toString().replace("-", "").trim()
        orderQueue.add(CoinOrderBean(3, sn, amount, coins1, coins2))
    }

    /**
     * 存币
     * @param open true-打开 false-关闭
     */
    fun saveCoins(open: Boolean){
        if (open) {
            if (handling) {
                return
            }
            orderQueue.add(CoinOrderBean(2, "", 0, 0, 0))
        }else{
            handling = false
            saveEnable(false)
        }
    }

    override fun cmdTimeout(comData: ComData) {
        logFile("指令响应超时：${comData.data} ")
    }

//    override fun sendCmd(msg: String) {
//        logFile("发送指令：$msg")
//    }

    private var serialControllerListener: SerialControllerListener? = null
    interface SerialControllerListener{
        /**
         * 心跳数据回调
         */
        fun heartBeat(isConnect: Boolean, stateCode: Int, errCode: Int)

        /**
         * 出币数异常回调
         */
        fun countErr(count: Long)

        /**
         * 马达出币超时回到
         */
        fun motorTimeout(motorNumber: Int)

        /**
         * 清币回调
         */
        fun onClearCoin(clearFinish: Boolean, clearCoinCount: Long)

        /**
         * 出币数据回调
         */
        fun outCoinFinish(remainCount: Long, currentOutCount: Long, outFinish: Boolean)

        /**
         * 马达故障
         */
        fun onMotorErr(motorNumber: Int)

        /**
         * 存币结束
         */
        fun saveCoinFinish(count: Long)

        /**
         * 刷新出币或存币数据
         */
        fun onCoinRefresh(coinCount: Long, needOutCoins: Long, outOrSave: Boolean)

        /**
         * 控制板接收订单
         */
        fun onOutRec()

        /**
         * 出币结果
         */
        fun onOutResult(msg: String)
    }

    fun setSerialControllerListener(listener: SerialControllerListener){
        this.serialControllerListener = listener
    }

}